/**
 * Created by Forcs on 15/7/31.
 */
(function($) {

  var copyDefaultAttr = function(option, def) {
    if (option === def) {
      return;
    }

    for (var key in def) {
      if (!option[key]) {
        option[key] = def[key];
      }
    }
  };

  /**
   * 动态将数据填充到table中
   * @param option
   * @returns {
   * {
   * load: Function
   * , loadFromUrl: Function
   * , onLoad: Function
   * , onFail: Function
   * , onDone: Function
   * }
   * }
   */
  $.fn.table = function(option) {

    var _self = $(this);


    var _loadDoneListener = null;
    var _loadSuccessListener = null;
    var _loadFailListener = null;
    var _rowClickListener = null;
    var _cellClickListener = null;
    var _projectionClickListener = null;

    var _table = {};
    var _option = null;

    var defaultOption = {
      columnKeys : []
      , columnNames : []
      , getColumnName : function(key) {
        return null;
      }
      , columnHeader : function(key, name) {
        return name;
      }
      , columnBody : function(key, value, data, rowNumber) {
        return value;
      }
    };

    var readDefault = function(option, def) {
      copyDefaultAttr(option, def);
    };

    var checkRequire = function(option) {
      if (!option.columnKeys || option.columnKeys.length == 0) {
        return false;
      }
      return true;
    };

    var initTable = function (option) {
      var keys = option.columnKeys;
      var names = option.columnNames;
      var keysCount = keys.length;
      _table.size = 0;
      _table.column = {}
      for (var i = 0; i < keysCount; i++) {
        var key = keys[i];
        _table.column[key] = {};
        _table.column[key].name = names[i];
        _table.column[key].data = [];
      }
    };

    var init = function(option) {
      _option = option || defaultOption;

      readDefault(_option, defaultOption);

      if (!checkRequire(_option)) {
        return undefined;
      }

      if (!_option.columnNames) {
        _option.columnNames = [];
        var funcGetColumnName = _option.getColumnName;
        if (funcGetColumnName && typeof funcGetColumnName == 'function') {
          var colKeys = _option.columnKeys;
          if (colKeys) {
            var N = colKeys.length;
            for (var i = 0; i < N; i++) {
              var name = funcGetColumnName.apply(_self, colKeys[i]);
              if (name) {
                _option.columnNames.push(name)
              }
            }
          }
        }
      }

      initTable(_option);

      createHeader();
    };

    //创建每列的列头
    var createHeader = function() {
      var table = _table;
      var option = _option;
      var theader = $("<thead />");
      var tr = $("<tr />");
      var column = table.column;
      for (var key in column) {
        var td = $("<td />");
        td.data("key", key);
        td.html(option.columnHeader(key, column[key].name));

        td.click(function(e) {
          if ($.isFunction(_projectionClickListener)) {
            var projection = $(this).data("key");
            _projectionClickListener.apply(_self, [projection]);
          }
        });
        tr.append(td);
      }
      theader.append(tr);
      _self.append(theader);
    };

    //填充数据到表格中
    var fillBody = function() {
      var option = _option;
      var table = _table;
      var tbody = _self.find("tbody");

      if (!tbody.length) {
        tbody = $("<tbody />");
        _self.append(tbody);
      }

      //先将数据填充到已有的tr中
      tbody.children("tr").each(function(trIndex, trItem) {

        if (trIndex >= _table.src.length) {
          return false;
        }

        $(trItem).children("td").each(function(tdIndex, tdItem) {

          var key = $(tdItem).data("key");
          var column = table.column;
          var value = column[key].data[trIndex];
          $(tdItem).empty();
          if ($.isFunction(option.columnBody)) {
            $(tdItem).html(option.columnBody.apply(_self, [key, value, _table.src[trIndex], trIndex]))
          } else {
            $(tdItem).text(value);
          }
        });
      });

      //比较新数据和当前数据集合大小
      //如果新数据集合比旧数据小，就讲多余的tr移除
      //如果新数据集合比旧数据大，则添加新的tr，并
      //将数据填充到tr中
      var trs = tbody.find("tr");
      var oldLength = trs.length || 0;
      var newLength = table.size;
      var delta = newLength - oldLength;
      if (delta > 0) {  //新数据集合比旧数据大
        for (var i = 0; i < delta; i++) {
          //添加新的tr
          var tr = $("<tr />");
          var pos = oldLength + i;
          tr.data("position", pos);
          var column = table.column;
          for (var key in column) {
            var td = $("<td />");
            var value = column[key].data[i + oldLength];
            td.data("key", key);
            td.data("row", pos);
            if ($.isFunction(option.columnBody)) {
              td.html(option.columnBody.apply(_self, [key, value, _table.src[i + oldLength], i + oldLength]))
            } else {
              td.text(value);
            }

            td.click(function(e) {
              var _this = this;
              var cellKey = $(_this).data("key");
              var cellRow = $(_this).data("row");
              if ($.isFunction(_cellClickListener)) {
                var handled = _cellClickListener.apply(_self, [_this, cellKey, cellRow, _table.src[cellRow]]);
                if (handled) {
                  return false;
                }
              }
            });

            tr.append(td);
          }

          tr.click(function(e) {
            var _this = this;
            var pos = $(this).data("position");
            if ($.isFunction(_rowClickListener)) {
              _rowClickListener.apply(_self, [_this, pos, _table.src[pos]]);
            }
          });

          tbody.append(tr);
        }
      } else if (delta < 0) { //新数据集合比旧数据小
        delta = -delta;
        for (var i = 0; i < delta; i++) {
          //将多余的移除
          trs[oldLength - 1 - i].remove();
        }
      }
    };

    var reload = function(data) {
      if (!$.isArray(data)) {
        return;
      }

      var table = _table;
      var column = table.column;
      for (var key in column) {
        column[key].data = [];
      }

      table.size = data.length;
      table.src = data;

      for (var i = 0; i < data.length; i++) {
        var item = data[i];
        for (var key in column) {
          column[key].data.push(item[key]);
        }
      }
    };

    init(option);

    var obj = {
      load : function(data) {
        reload(data);
        fillBody();
      }
      , loadFromUrl : function(request) {
        var self = this;
        $.ajax(request.url, {
          data : request.params
          , type : "GET"
          , dataType : "json"
          , success : function(data) {
            if ($.isFunction(_loadSuccessListener)) {
              _loadSuccessListener.apply(self, [self, data]);
            }
            if ($.isFunction(_loadDoneListener)) {
              _loadDoneListener.apply(self, [self, true, data])
            }
          }
          , error : function() {
            if ($.isFunction(_loadFailListener)) {
              _loadFailListener.apply(self, [self]);
            }
            if ($.isFunction(_loadDoneListener)) {
              _loadDoneListener.apply(self, [self, false])
            }
          }
        });
        return self;
      }
      , onLoad : function(listener) {
        _loadSuccessListener = listener;
        return this;
      }
      , onFail : function(listener) {
        _loadFailListener = listener;
        return this;
      }
      , onDone : function(listener) {
        _loadDoneListener = listener;
        return this;
      }
      , onRowClick : function(listener) {
        _rowClickListener = listener;
        return this;
      }
      , onCellClick : function(listener) {
        _cellClickListener = listener;
        return this;
      }
      , onProjectionClick : function(listener) {
        _projectionClickListener = listener;
        return this;
      }

    };

    return obj;
  };

  /**
   * 翻页
   * @param option
   * @returns {
   *  {
   *  getTotal: Function
   *  , getCurrent: Function
   *  , first: Function
   *  , last: Function
   *  , next: Function
   *  , previous: Function
   *  , page: Function
   *  , onSelectPage: Function}
   *  }
   */
  $.fn.pager = function(option) {

    var DEF_SHOW_COUNT = 7;

    var FLAG_FIRST = 1;
    var FLAG_PREVIOUS = 2;
    var FLAG_NEXT = 3;
    var FLAG_LAST = 4;
    var FLAG_NORMAL = 0;

    var DATA_KEY_FLAG = "page-flag";
    var DATA_KEY_NUMBER = "page-number";

    var defaultOption = {
      showCount : DEF_SHOW_COUNT
      , total : 0
      , current : 1
      , align : "left"
    };

    var _self = $(this);
    //选中监听器
    var _selectPageListener = null;
    var _option = option || defaultOption;

    copyDefaultAttr(_option, defaultOption);

    var buildPageItem = function(content, flag) {
      var li = $("<li />");
      li.data(DATA_KEY_FLAG, flag);
      var a = $("<a />");
      a.attr({
        href : "#"
      });
      a.html(content);
      li.append(a);
      li.click(function(e) {
        var page = $(this).data(DATA_KEY_NUMBER);
        update(page);
        if ($.isFunction(_selectPageListener)) {
          _selectPageListener.apply(_self, [page])
        }
      });

      return li;
    };

    var updatePageItem = function(li, number) {
      li.data(DATA_KEY_NUMBER, number);
      var a = $(li).find("a");
      $(a).html(number);
    };

    var buildFirstPageItem = function() {
      return buildPageItem("&laquo", FLAG_FIRST);
    };

    var buildLastPageItem = function() {
      return buildPageItem("&raquo;", FLAG_LAST);
    };

    var buildPreviousPageItem = function() {
      return buildPageItem("&lsaquo;", FLAG_PREVIOUS);
    };

    var buildNextPageItem = function() {
      return buildPageItem("&rsaquo;", FLAG_NEXT);
    };

    var init = function() {
      _option.showCount = Math.min(_option.total, _option.showCount);
      var showCount = _option.showCount;

      var nav = $("<nav />");
      if (_option.align) {
        $(nav).css({
          "text-align": _option.align
        });
      }
      var ul = $("<ul />")
          .addClass("pagination")
          .addClass("wb-pagination");
      nav.append(ul);

      ul.append(buildFirstPageItem());
      ul.append(buildPreviousPageItem());
      for (var i = 0; i < showCount; i++) {
        ul.append(buildPageItem(i, FLAG_NORMAL));
      }
      ul.append(buildNextPageItem());
      ul.append(buildLastPageItem());

      _self.append(nav);

      update(_option.current);
    };

    var update = function(current) {

      current = Math.max(1, current);
      current = Math.min(_option.total, current);

      var showCount = _option.showCount;
      var total = _option.total;
      var nav = _self.find("nav");
      var ul = $(nav).find("ul");
      var halfLeft = parseInt(showCount / 2);
      if (current <= halfLeft) {
        halfLeft = current - 1;
      }
      var halfRight = showCount - 1 - halfLeft;
      if (current + halfRight > total) {
        halfRight = total - current;
      }
      if (halfLeft + 1 + halfRight < showCount) {
        halfLeft = showCount - halfRight - 1;
      }

      var start = current - halfLeft;

      var offset = -1;
      $(ul).children("li").each(function(index, liItem) {
        var li = $(liItem);
        var flag = li.data(DATA_KEY_FLAG);

        switch (flag) {
          case FLAG_FIRST:
            li.data(DATA_KEY_NUMBER, 1);
            break;
          case FLAG_LAST:
            li.data(DATA_KEY_NUMBER, total);
            break;
          case FLAG_NEXT:
            li.data(DATA_KEY_NUMBER, current + 1);
            break;
          case FLAG_PREVIOUS:
            li.data(DATA_KEY_NUMBER, current - 1);
            break;
          case FLAG_NORMAL:
            if (offset < 0) {
              offset = index;
            }
            updatePageItem(li, start + index - offset);

            var page = li.data(DATA_KEY_NUMBER);
            if (current == page) {
              if (!li.hasClass("active")) {
                li.addClass("active");
              }
            } else {
              if (li.hasClass("active")) {
                li.removeClass("active");
              }
            }
            break;
        }

      });
      _option.current = current;
    };

    init();

    var obj = {
      getTotal : function() {
        return _option.total;
      }
      , getCurrent : function() {
        return _option.current;
      }
      , first : function() {
        update(1);
      }
      , last : function() {
        update(_option.total);
      }
      , next : function() {
        update(_option.current + 1);
      }
      , previous : function() {
        update(_option.current - 1);
      }
      , page : function(number) {
        update(number);
      }
      , onSelectPage : function(selectPageListener) {
        _selectPageListener = selectPageListener;
        return this;
      }
    };

    return obj;
  };

  /**
   * 添加fa图标
   * @param iconName 去掉fa前缀的名称
   * @param isSpin 是否需要添加fa-spin类，让图片动起来
   * @returns {jQuery}
   */
  $.fn.icon = function(iconName, isSpin) {
    var FA_SPIN_CLASS = "fa-spin";
    var i = $(this).find("i");
    if (i && i.length) {
      $(i).each(function(index, item) {
        var $it = $(item);
        if ($it.hasClass("fa")) {
          $it.removeClass();
          $it.addClass("fa fa-" + iconName);
          if (isSpin) {
            $it.addClass(FA_SPIN_CLASS)
          }
        }
      });
    } else {
      i = $("<i />").addClass("fa fa-" + iconName);
      if (isSpin) {
        i.addClass("fa-spin");
      }
      $(this).append(i);
    }

    return this;
  };

  /**
   * 标记激活
   * @returns {jQuery}
   */
  $.fn.active = function() {
    if (!$(this).hasClass("active")) {
      $(this).addClass("active");
    }
    return this;
  };

  /**
   * 取消激活
   * @returns {jQuery}
   */
  $.fn.normal = function() {
    if ($(this).hasClass("active")) {
      $(this).removeClass("active");
    }
    return this;
  };

  /**
   * tab按钮组
   * @param option
   * @returns {
   * {
   * getCount: Function
   * , onItemSelectedListener: Function}
   * }
   */
  $.fn.tabGroup = function(option) {

    var initButtons = function(option, defButton) {
      if (option.count <= 0) {
        return;
      }

      var count = option.count;
      if (!option.buttons || !option.buttons.length) {
        option.buttons = [];
        for (var i = 0; i < count; i++) {
          var item = {};
          if (option.buttonTexts[i]) {
            item.text = option.buttonTexts[i];
          }
          if (option.buttonIds[i]) {
            item.id = option.buttonIds[i];
          }
          if (option.buttonIcons[i]) {
            item.icon = option.buttonIcons[i];
          }
          option.buttons.push(item);
        }
      } else {
        var buttons = option.buttons;
        for (var i = 0; i < count; i++) {
          var item = buttons[i];
          copyDefaultAttr(item, defButton)
        }

      }
    };

    var buildButton = function(btnObj, position) {
      var button = $("<button />")
          .addClass("btn")
          .addClass("btn-default")
          .attr({
            "type" : "button"
          });
      button.data("button-id", btnObj.id);
      button.data("button-position", position);

      if (btnObj.icon) {
        $(button).icon(btnObj.icon);
      }
      button.append(btnObj.text);
      return button;
    };

    var init = function(option) {
      var wrapper = $("<div />")
          .addClass("btn-group")
          .attr({
            "role" : "group"
          });
      var buttons = option.buttons;
      var count = option.count;
      var activeId = option.activeId;
      for (var i = 0; i < count; i++) {
        var item = buttons[i];
        var button = buildButton(item, i);
        $(button).click(function(e) {
          var _this = this;
          var id = $(_this).data("button-id");
          var position = $(_this).data("button-position");
          if ($.isFunction(_itemSelectedListener)) {
            _itemSelectedListener.apply(_self, [_self, _this, id, position])
          }

          if (_currentActive) {
            $(_currentActive).normal();
          }

          _currentActive = _this;
          $(_currentActive).active();
        });

        wrapper.append(button);

        if (activeId) {
          if (item.id == activeId) {
            $(button).active();
            _currentActive = button;
          }
        } else {
          if (i == 0) {
            $(button).active();
            _currentActive = button;
          }
        }
      }

      _self.append(wrapper);
    };

    var defaultOption = {
      count : 0
      , buttons : []
      , buttonTexts : []
      , buttonIds : []
      , buttonIcons : []
      , activeId : undefined
    };

    var defaultButton = {
      text : ""
      , id : -1
      , icon : null
    };

    var _self = $(this);
    var _option = option || defaultOption;
    //选中监听器
    var _itemSelectedListener = null;
    //当前激活的按钮
    var _currentActive = null;

    copyDefaultAttr(_option, defaultOption);

    initButtons(_option, defaultButton);
    init(_option);

    var obj = {
      getCount : function() {
        return _option.count;
      }
      , onItemSelected : function(listener) {
        _itemSelectedListener = listener;
        return this;
      }
    };

    return obj;
  };

  /**
   * 提示控件
   * @param option
   * @returns {{icon: Function, text: Function, show: Function, hide: Function}}
   */
  $.fn.hint = function(option) {

    var isEmptyOption = function(option) {
      return !option.icon && !option.text
    };

    var init = function(option) {
      update(option);
      _self.hide();
    };

    var update = function(option) {
      _self.empty();
      if (option.icon) {
        _self.icon(option.icon, option.spinIcon);
      }

      if (option.text) {
        var html = _self.html();
        if (html) {
          html += option.text;
        } else {
          html = option.text;
        }
        _self.html(html);
      }
    };

    var defaultOption = {
      icon : null
      , text : null
      , spinIcon : false
    };

    var _self = $(this);
    var _option = option || defaultOption;

    copyDefaultAttr(_option, defaultOption);

    if (!isEmptyOption(_option)) {
      init(option);
    }

    var obj = {
      icon : function(iconName, isSpin) {
        _option.icon = iconName;
        _option.spinIcon = isSpin;
        update(_option);
        return this;
      }
      , text : function(text) {
        _option.text = text;
        update(_option);
        return this;
      }
      , show : function() {
        _self.show();
      }
      , hide : function() {
        _self.hide();
      }
    };

    return obj;
  };

  $.fn.button = function() {

    var _self = $(this);
    var _clickListener = null;

    _self.click(function(e) {
      var handled = false;
      if ($.isFunction(_clickListener)) {
        handled = _clickListener.apply(_self, [_self, e]);
      }
      if (!handled) {
        var url = _self.data("wb-url");
        if (url) {
          window.location.href = url;
          return false
        }
      } else {
        return false;
      }

    });

    var obj = {
      click : function(l) {
        _clickListener = l;
        return this;
      }
    };
    return obj;
  }

})(jQuery);